package com.xjgc.rest;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xjgc.msibase.entity.MsiExoSystemServer;
import com.xjgc.msibase.entity.MsiServerRecordInfo;
import com.xjgc.msibase.service.IMsiServerRecordInfoService;
import com.xjgc.msibase.vo.MsiServerTaskExoServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.SpringContextUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 外围系统Rest服务调用
 *
 * @author: 小逗号
 * @date: 2023-11-14
 * @description:
 * @since:
 */
@Component
@Slf4j
public class ExoRestServerCall {
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private IMsiServerRecordInfoService msiServerRecordInfoService;

    /**
     * token 认证javaBean
     */
    private Map<String, Object> tokenServerMap = new HashMap<>(16);
    /**
     * token 认证javaBean 获取token方法名
     */
    private Map<String, Method> tokenMethodMap = new HashMap<>(16);
    private HttpHeaders headers = new HttpHeaders();
    /**
     *
     */
    private Map<String, String> headersMap;


    /**
     * 调用外系统Rest服务
     *
     * @param taskVo
     * @param param
     * @return
     */
    public Result requestExoServer(String recordId, MsiServerTaskExoServer taskVo, JSON param) {
        String url = taskVo.getRestAddress();
        String jsonKey = taskVo.getJsonKey();
        if (StringUtils.isNotBlank(jsonKey)) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put(jsonKey, param);
            param = jsonObject;
        }
        HttpHeaders httpHeaders = null;
        if (taskVo.isSecret()) {
            String tokenMode = taskVo.getTokenMode();
            if (MsiExoSystemServer.BODY.equals(tokenMode)) {
                if (param instanceof JSONArray) {
                    msiServerRecordInfoService.add(recordId, new Date(), MsiServerRecordInfo.Node.ZF_REST, "中间库分发任务" + taskVo.getExoServerCode() + "配置错误,requestBody json is array ,can not set token!");
                    return Result.error("中间库分发任务" + taskVo.getExoServerCode() + "配置错误,requestBody json is array ,can not set token!");
                }
            }
            String tokenKey = taskVo.getTokenKey();
            String token = getToken(taskVo.getTokenClass());
            msiServerRecordInfoService.add(recordId, new Date(), MsiServerRecordInfo.Node.REST_TOKEN);
            if (MsiExoSystemServer.HEARD.equals(tokenMode)) {
                httpHeaders = getHttpHeaders(tokenKey, token);
            } else {
                JSONObject jsonObject = (JSONObject) param;
                jsonObject.put(tokenKey, token);
                param = jsonObject;
            }
        }
        Result request = this.request(recordId, url, param, httpHeaders);
        return request;

    }


    private Result request(String recordId, String url, JSON body, HttpHeaders headers) {
        log.info("发送Rest请求POST==>{}", url);
        try {
            JSONObject response;
            msiServerRecordInfoService.add(recordId, new Date(), MsiServerRecordInfo.Node.ZF_REST, url, JSON.toJSONString(body));
            if (headers != null) {
                response = restTemplate.postForObject(url, new HttpEntity(body, headers), JSONObject.class);
                if (response == null || response.size() == 0) {
                    String res = restTemplate.postForObject(url, body, String.class);
                    log.warn(res);
                    response = JSON.parseObject(res);
                }
            } else {
                response = restTemplate.postForObject(url, body, JSONObject.class);
                if (response == null || response.size() == 0) {
                    String res = restTemplate.postForObject(url, body, String.class);
                    log.warn(res);
                    response = JSON.parseObject(res);
                }
            }
            msiServerRecordInfoService.add(recordId, new Date(), MsiServerRecordInfo.Node.ZF_REST_RES, "", JSON.toJSONString(response));
            return Result.OK(response);
        } catch (RestClientException e) {
            log.error("转发失败.", e);
            msiServerRecordInfoService.add(recordId, new Date(), MsiServerRecordInfo.Node.ZF_REST_RES, "转发失败," + url + e.getMessage());
            return Result.error("转发失败," + url + e.getMessage());
        }
    }


    /**
     * 获取认证Token
     *
     * @param tokenClass
     * @return
     */
    private String getToken(String tokenClass) {
        if (!tokenServerMap.containsKey(tokenClass)) {
            try {
                Class<?> aClass = Class.forName(tokenClass);
                Object bean = SpringContextUtils.getBean(aClass);
                tokenServerMap.put(tokenClass, bean);
                Method method = aClass.getMethod("getToken");
                tokenMethodMap.put(tokenClass, method);
            } catch (ClassNotFoundException | NoSuchMethodException e) {
                log.error("类加载失败:" + tokenClass, e);
                throw new JeecgBootException("中间库任务执行失败!");
            }
        }
        Object o = tokenServerMap.get(tokenClass);
        Method method = tokenMethodMap.get(tokenClass);
        try {
            Object invoke = method.invoke(o);
            return invoke.toString();
        } catch (IllegalAccessException | InvocationTargetException e) {
            log.error("类加载失败:" + tokenClass, e);
            throw new JeecgBootException("中间库任务执行失败!");
        }
    }

    private HttpHeaders getHttpHeaders(String key, String value) {
        if (headersMap == null) {
            headersMap = new HashMap<>(4);
            headersMap.put("Accept", "application/json");
            headersMap.put("Content-Encoding", "UTF-8");
            headersMap.put("Content-Type", "application/json; charset=UTF-8");
        }
        headersMap.put(key, value);
        headers.setAll(headersMap);
        return headers;
    }
}
